package com.wall.haven.service;

import com.wall.haven.config.SystemConfigCache;
import com.wall.haven.constant.RegExConstants;
import com.wall.haven.exception.ServiceException;
import com.wall.haven.util.AESUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class ProxyService {

    /**
     * logger
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(ProxyService.class);

    @Value("${proxy.api-host}")
    private String apiHost;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IBanImageService banImageService;

    @Autowired
    private SystemConfigCache systemConfigCache;

    /**
     * 转发api
     *
     * @param request
     * @return
     */
    public ResponseEntity<Object> proxyApi(HttpServletRequest request) {
        String path = request.getRequestURI();
        String query = request.getQueryString();
        if (!systemConfigCache.isNsfw()) {
            String purity = request.getParameter("purity");
            if (!StringUtils.isEmpty(purity)) {
                int parsePurity = Integer.parseInt(purity, 2);
                parsePurity = parsePurity & 0b110;
                query = query.replaceAll("&purity=\\d{3}(&|$)", "purity=" + String.format("%03d", Integer.parseInt(Integer.toBinaryString(parsePurity))));
            }
        }
        String urlStr = "https://" + apiHost + path.replace("/proxy/api", "");
        if (!ObjectUtils.isEmpty(query)) {
            urlStr = urlStr + "?" + query;
        }
        // 执行远程调用
        try {
            // 发送GET请求
            ResponseEntity<Object> entity = restTemplate.getForEntity(urlStr, Object.class);
            return ResponseEntity
                    .status(entity.getStatusCode())
                    .body(entity.getBody());
        } catch (HttpClientErrorException e) {
            return ResponseEntity.status(e.getStatusCode())
                    .body(e.getResponseBodyAsString());
        } catch (Exception e) {
            throw new ServiceException("转发请求失败", e);
        }
    }

    /**
     * 转发图片
     *
     * @param imageUrl
     * @return
     * @throws URISyntaxException
     * @throws IOException
     */
    public void proxyImage(String imageUrl, HttpServletResponse response) throws URISyntaxException, IOException {
        imageUrl = AESUtil.decrypt(imageUrl, systemConfigCache.getAesKey());
        if (!imageUrl.contains(apiHost) || banImageService.isBannedUrl(imageUrl)) {
            throw new ServiceException("禁止访问");
        }
        MediaType mediaType = MediaType.IMAGE_PNG;
        if (imageUrl.endsWith(".jpg")) {
            mediaType = MediaType.IMAGE_JPEG;
        }
        if (imageUrl.endsWith(".png")) {
            mediaType = MediaType.IMAGE_PNG;
        }
        response.setHeader(HttpHeaders.CONTENT_TYPE, mediaType.toString());
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "filename=\"" + getFileName(imageUrl) + "\"");
        try (InputStream inputStream = new URL(imageUrl).openStream()) {
            int contentLength = StreamUtils.copy(inputStream, response.getOutputStream());
            LOGGER.debug("图片大小：" + contentLength);
            response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength));
        } catch (Exception e) {
            throw new ServiceException("打开图片失败", e);
        }
    }

    public void test(String path, HttpServletResponse response) {
        response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.IMAGE_JPEG.toString());
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "filename=\"" + getFileName(path) + "\"");
        try {
            try (InputStream inputStream = new URL(path).openStream()) {
                long contentLength = StreamUtils.copy(inputStream, response.getOutputStream());
                LOGGER.debug("图片大小：" + contentLength);
                response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength));
            } catch (Exception e) {
                throw new ServiceException("打开图片失败", e);
            }
        } catch (Exception e) {
            throw new ServiceException("打开图片失败", e);
        }
    }

    private byte[] toByteArray(InputStream in) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try {
            byte[] bytes = new byte[1024];
            int n;
            while ((n = in.read(bytes)) != -1) {
                byteArrayOutputStream.write(bytes, 0, n);
            }
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return byteArrayOutputStream.toByteArray();
    }

    private String getFileName(String imageUrl) {
        Pattern pattern = Pattern.compile(RegExConstants.GET_IMAGE_FILE_REGEX);
        Matcher matcher = pattern.matcher(imageUrl);
        // 提取文件名
        if (matcher.find()) {
            return matcher.group(1);
        } else {
            return "";
        }
    }
}
